import axios, { AxiosRequestConfig, AxiosProgressEvent } from 'axios';
import { KSpaceConfig, UploadOptions, UploadResult, FileInfo } from '../types';
import { IKSpaceClient } from '../types/client';
import { generateSignature, generateRandomString } from '../utils/crypto';
import { buildRequestUrl, validateConfig, generateFileUrl } from '../utils/helper';

/**
 * KSpace OSS客户端实现类
 */
export class KSpaceClient implements IKSpaceClient {
  public config: KSpaceConfig;

  /**
   * 构造函数
   * @param config 配置信息
   */
  constructor(config: KSpaceConfig) {
    // 验证配置
    validateConfig(config);
    
    // 设置默认值
    this.config = {
      secure: true,
      ...config
    };
  }

  /**
   * 上传单个文件
   * @param options 上传选项
   * @returns Promise<UploadResult>
   */
  public async upload(options: UploadOptions): Promise<UploadResult> {
    try {
      const { file, key, storageClass = 'Standard', meta, onProgress } = options;
      const resource = `/${key}`;
      
      // 准备请求头
      const headers: Record<string, string> = {
        'Content-Type': this.getContentType(file),
        'x-oss-storage-class': storageClass,
        'x-oss-meta-uploader': 'kspace-client',
        'x-oss-date': new Date().toISOString(),
        'x-oss-content-disposition': `inline; filename="${encodeURIComponent(this.getFileName(file))}"`
      };
      
      // 添加自定义元数据
      if (meta) {
        Object.entries(meta).forEach(([k, v]) => {
          headers[`x-oss-meta-${k}`] = v;
        });
      }
      
      // 生成签名
      const signature = generateSignature(this.config, 'PUT', resource, headers);
      headers['Authorization'] = signature;
      
      // 构建请求配置
      const requestConfig: AxiosRequestConfig = {
        method: 'PUT',
        url: buildRequestUrl(this.config, `${this.config.bucket}${resource}`),
        headers,
        data: file,
        onUploadProgress: (progressEvent: AxiosProgressEvent) => {
          if (onProgress && progressEvent.total) {
            const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            onProgress(progress, progressEvent.total, progressEvent.loaded);
          }
        },
        timeout: 60000
      };
      
      // 发送请求
      const response = await axios(requestConfig);
      
      // 构建返回结果
      const result: UploadResult = {
        key,
        url: generateFileUrl(this.config, key),
        size: this.getFileSize(file),
        uploadedAt: Date.now(),
        etag: response.headers.etag
      };
      
      return result;
    } catch (error: any) {
      this.handleError(error);
      throw error;
    }
  }

  /**
   * 批量上传文件
   * @param files 文件数组
   * @returns Promise<UploadResult[]>
   */
  public async uploadFiles(files: Array<Omit<UploadOptions, 'file'>> & { file: File | Buffer }[]): Promise<UploadResult[]> {
    const uploadPromises = (files as any[]).map(fileOptions => this.upload(fileOptions));
    return Promise.all(uploadPromises);
  }

  /**
   * 获取文件信息
   * @param key 文件路径
   * @returns Promise<FileInfo>
   */
  public async getFileInfo(key: string): Promise<FileInfo> {
    try {
      const resource = `/${key}`;
      const headers: Record<string, string> = {
        'x-oss-date': new Date().toISOString()
      };
      
      // 生成签名
      const signature = generateSignature(this.config, 'HEAD', resource, headers);
      headers['Authorization'] = signature;
      
      const response = await axios({
        method: 'HEAD',
        url: buildRequestUrl(this.config, `${this.config.bucket}${resource}`),
        headers
      });
      
      return {
        key,
        size: parseInt(response.headers['content-length'] || '0'),
        lastModified: new Date(response.headers['last-modified']),
        etag: response.headers.etag,
        contentType: response.headers['content-type'],
        storageClass: response.headers['x-oss-storage-class']
      };
    } catch (error: any) {
      this.handleError(error);
      throw error;
    }
  }

  /**
   * 删除文件
   * @param key 文件路径
   * @returns Promise<boolean>
   */
  public async deleteFile(key: string): Promise<boolean> {
    try {
      const resource = `/${key}`;
      const headers: Record<string, string> = {
        'x-oss-date': new Date().toISOString()
      };
      
      // 生成签名
      const signature = generateSignature(this.config, 'DELETE', resource, headers);
      headers['Authorization'] = signature;
      
      await axios({
        method: 'DELETE',
        url: buildRequestUrl(this.config, `${this.config.bucket}${resource}`),
        headers
      });
      
      return true;
    } catch (error: any) {
      this.handleError(error);
      throw error;
    }
  }

  /**
   * 获取文件URL
   * @param key 文件路径
   * @param expires 过期时间（秒）
   * @returns 文件URL
   */
  public getFileUrl(key: string, expires?: number): string {
    return generateFileUrl(this.config, key, expires);
  }

  /**
   * 列出文件
   * @param prefix 前缀
   * @param maxKeys 最大数量
   * @returns Promise<FileInfo[]>
   */
  public async listFiles(prefix?: string, maxKeys: number = 100): Promise<FileInfo[]> {
    try {
      const resource = '/';
      const headers: Record<string, string> = {
        'x-oss-date': new Date().toISOString()
      };
      
      // 生成签名
      const signature = generateSignature(this.config, 'GET', resource, headers);
      headers['Authorization'] = signature;
      
      const params: any = {
        prefix: prefix || '',
        maxKeys
      };
      
      const response = await axios({
        method: 'GET',
        url: buildRequestUrl(this.config, this.config.bucket),
        headers,
        params
      });
      
      // 处理XML响应（简化版，实际应该使用XML解析器）
      // 这里返回空数组，实际项目中需要解析XML响应
      return [];
    } catch (error: any) {
      this.handleError(error);
      throw error;
    }
  }

  /**
   * 获取文件类型
   * @param file 文件对象
   * @returns 文件MIME类型
   */
  private getContentType(file: File | Buffer): string {
    if (typeof File !== 'undefined' && file instanceof File) {
      return file.type || 'application/octet-stream';
    }
    return 'application/octet-stream';
  }

  /**
   * 获取文件大小
   * @param file 文件对象
   * @returns 文件大小（字节）
   */
  private getFileSize(file: File | Buffer): number {
    if (typeof File !== 'undefined' && file instanceof File) {
      return file.size;
    }
    if (Buffer.isBuffer(file)) {
      return file.length;
    }
    return 0;
  }

  /**
   * 获取文件名
   * @param file 文件对象
   * @returns 文件名
   */
  private getFileName(file: File | Buffer): string {
    if (typeof File !== 'undefined' && file instanceof File) {
      return file.name;
    }
    return generateRandomString(10);
  }

  /**
   * 错误处理
   * @param error 错误对象
   */
  private handleError(error: any): void {
    if (error.response) {
      // 服务器返回错误状态码
      const { status, statusText, data } = error.response;
      console.error(`OSS API Error: ${status} ${statusText}`, data);
    } else if (error.request) {
      // 请求已发出但没有收到响应
      console.error('No response received from OSS server', error.request);
    } else {
      // 请求配置出错
      console.error('Error setting up request', error.message);
    }
  }
}